#include "MathCEF.h"
#ifdef ALICE_JS_CEF_PORT
#include "Runtime/Log/Logger.h"
#include "Runtime/Math/Matrix.h"
#include "Runtime/Math/Quaternion.h"
namespace Alice{
    bool Math::Execute(const CefString& name,
        CefRefPtr<CefV8Value> object,
        const CefV8ValueList& arguments,
        CefRefPtr<CefV8Value>& retval,
        CefString& exception) {
        if (name == "MNMatrix") {
            float scaleX=float(arguments[0]->GetDoubleValue());
            float scaleY=float(arguments[1]->GetDoubleValue());
            float scaleZ=float(arguments[2]->GetDoubleValue());
            float rotateX=float(arguments[3]->GetDoubleValue());
            float rotateY=float(arguments[4]->GetDoubleValue());
            float rotateZ=float(arguments[5]->GetDoubleValue());
            float positionX=float(arguments[6]->GetDoubleValue());
            float positionY=float(arguments[7]->GetDoubleValue());
            float positionZ=float(arguments[8]->GetDoubleValue());
            Matrix3 scale;
            scale.LoadIdentity();
            scale.SetScale(scaleX,scaleY,scaleZ);
            Matrix3 lt3x3=scale*Quaternion(rotateX,rotateY,rotateZ).toMatrix3();

            Matrix4 mnMatrix[2];
            mnMatrix[0].LoadIdentity();
            mnMatrix[0].SetLeftTop3x3(lt3x3);
            mnMatrix[0].Tranlate(positionX, positionY, positionZ);

            mnMatrix[1].LoadIdentity();
            //invert -> transpose
            mnMatrix[1].SetLeftTop3x3(lt3x3);
            mnMatrix[1]._14=-positionX;
            mnMatrix[1]._24=-positionY;
            mnMatrix[1]._34=-positionZ;

            retval=CefV8Value::CreateArrayBufferWithCopy(mnMatrix,sizeof(mnMatrix));
            return true;
        }
        else if (name == "LookAt") {
            float inPositionX=float(arguments[0]->GetDoubleValue());
            float inPositionY=float(arguments[1]->GetDoubleValue());
            float inPositionZ=float(arguments[2]->GetDoubleValue());
            float inTargetX=float(arguments[3]->GetDoubleValue());
            float inTargetY=float(arguments[4]->GetDoubleValue());
            float inTargetZ=float(arguments[5]->GetDoubleValue());
            float inUpX=float(arguments[6]->GetDoubleValue());
            float inUpY=float(arguments[7]->GetDoubleValue());
            float inUpZ=float(arguments[8]->GetDoubleValue());
            Matrix4 mat;
            mat.LookAt(float4(inPositionX,inPositionY,inPositionZ),float4(inTargetX,inTargetY,inTargetZ),float4(inUpX,inUpY,inUpZ,0.0f));
            
            retval=CefV8Value::CreateArrayBufferWithCopy(&mat,sizeof(mat));
            return true;
        }
        else if (name == "Perspective") {
            float fovInAngle=float(arguments[0]->GetDoubleValue());
            float aspect=float(arguments[1]->GetDoubleValue());
            float n=float(arguments[2]->GetDoubleValue());
            float f=float(arguments[0]->GetDoubleValue());
            Matrix4 mat;
            mat.Perspective(fovInAngle,aspect,n,f);
            retval=CefV8Value::CreateArrayBufferWithCopy(&mat,sizeof(mat));
            return true;
        }
        else {
            Debug("unprocessed function call [%s]",name.ToString().c_str());
        }
	    return false;
    }
    void Math::Export(CefRefPtr<CefV8Value> inScope){
        CefRefPtr<CefV8Value> fs = CefV8Value::CreateObject(nullptr, nullptr);
        CefRefPtr<Math> fsHandler = new Math;
        fs->SetValue("MNMatrix", CefV8Value::CreateFunction("MNMatrix", fsHandler), V8_PROPERTY_ATTRIBUTE_READONLY);
        fs->SetValue("LookAt", CefV8Value::CreateFunction("LookAt", fsHandler), V8_PROPERTY_ATTRIBUTE_READONLY);
        fs->SetValue("Perspective", CefV8Value::CreateFunction("Perspective", fsHandler), V8_PROPERTY_ATTRIBUTE_READONLY);
        inScope->SetValue("Math", fs, V8_PROPERTY_ATTRIBUTE_READONLY);
    }
}
#endif